Micron Document
🎖️GitЯра🎖️

Node / meshtastic / Meshtastic-Android / files / .specify / extensions / git / scripts / bash / create-new-feature.sh

Displaying Raw • Download

.specify/extensions/git/scripts/bash/create-new-feature.sh renovate/actions-checkout-7.x (2a019bd0) Text, 16.87 KB

T8b949e#!/usr/bin/env bash
T8b949e# Git extension: create-new-feature.sh
T8b949e# Adapted from core scripts/bash/create-new-feature.sh for extension layout.
T8b949e# Sources common.sh from the project's installed scripts, falling back to
T8b949e# git-common.sh for minimal git helpers.

Tffa657set -e

Te6edf3JSON_MODETff7b72=Tffa657false
Te6edf3DRY_RUNTff7b72=Tffa657false
Te6edf3ALLOW_EXISTINGTff7b72=Tffa657false
Te6edf3SHORT_NAMETff7b72=Ta5d6ff""
Te6edf3BRANCH_NUMBERTff7b72=Ta5d6ff""
Te6edf3USE_TIMESTAMPTff7b72=Tffa657false
Te6edf3ARGSTff7b72=Tff7b72(Tff7b72)
Te6edf3iTff7b72=T79c0ff1
Tff7b72while Tff7b72[ Te6edf3$i -le Te6edf3$# Tff7b72]Tb4b4b4; Tff7b72do
Te6edf3argTff7b72=Ta5d6ff"Tffd700${Tb4b4b4!iTffd700}Ta5d6ff"
Tff7b72case Ta5d6ff"Te6edf3$argTa5d6ff" Tff7b72in
--jsonTff7b72)
Te6edf3JSON_MODETff7b72=Tffa657true
Tb4b4b4;Tb4b4b4;
--dry-runTff7b72)
Te6edf3DRY_RUNTff7b72=Tffa657true
Tb4b4b4;Tb4b4b4;
--allow-existing-branchTff7b72)
Te6edf3ALLOW_EXISTINGTff7b72=Tffa657true
Tb4b4b4;Tb4b4b4;
--short-nameTff7b72)
Tff7b72if Tff7b72[ Tff7b72$((Te6edf3i Tff7b72+ T79c0ff1Tff7b72)) -gt Te6edf3$# Tff7b72]Tb4b4b4; Tff7b72then
Tffa657echo Ta5d6ff'Error: --short-name requires a value' >Tb4b4b4&T79c0ff2
Tffa657exit T79c0ff1
Tff7b72fi
Te6edf3iTff7b72=Tff7b72$((Te6edf3i Tff7b72+ T79c0ff1Tff7b72))
Te6edf3next_argTff7b72=Ta5d6ff"Tffd700${Tb4b4b4!iTffd700}Ta5d6ff"
Tff7b72if Tff7b72[Tff7b72[ Ta5d6ff"Te6edf3$next_argTa5d6ff" Tff7b72=Tff7b72= --* Tff7b72]Tff7b72]Tb4b4b4; Tff7b72then
Tffa657echo Ta5d6ff'Error: --short-name requires a value' >Tb4b4b4&T79c0ff2
Tffa657exit T79c0ff1
Tff7b72fi
Te6edf3SHORT_NAMETff7b72=Ta5d6ff"Te6edf3$next_argTa5d6ff"
Tb4b4b4;Tb4b4b4;
--numberTff7b72)
Tff7b72if Tff7b72[ Tff7b72$((Te6edf3i Tff7b72+ T79c0ff1Tff7b72)) -gt Te6edf3$# Tff7b72]Tb4b4b4; Tff7b72then
Tffa657echo Ta5d6ff'Error: --number requires a value' >Tb4b4b4&T79c0ff2
Tffa657exit T79c0ff1
Tff7b72fi
Te6edf3iTff7b72=Tff7b72$((Te6edf3i Tff7b72+ T79c0ff1Tff7b72))
Te6edf3next_argTff7b72=Ta5d6ff"Tffd700${Tb4b4b4!iTffd700}Ta5d6ff"
Tff7b72if Tff7b72[Tff7b72[ Ta5d6ff"Te6edf3$next_argTa5d6ff" Tff7b72=Tff7b72= --* Tff7b72]Tff7b72]Tb4b4b4; Tff7b72then
Tffa657echo Ta5d6ff'Error: --number requires a value' >Tb4b4b4&T79c0ff2
Tffa657exit T79c0ff1
Tff7b72fi
Te6edf3BRANCH_NUMBERTff7b72=Ta5d6ff"Te6edf3$next_argTa5d6ff"
Tff7b72if Tff7b72[Tff7b72[ ! Ta5d6ff"Te6edf3$BRANCH_NUMBERTa5d6ff" Tff7b72=~ ^Tff7b72[T79c0ff0-9Tff7b72]+$ Tff7b72]Tff7b72]Tb4b4b4; Tff7b72then
Tffa657echo Ta5d6ff'Error: --number must be a non-negative integer' >Tb4b4b4&T79c0ff2
Tffa657exit T79c0ff1
Tff7b72fi
Tb4b4b4;Tb4b4b4;
--timestampTff7b72)
Te6edf3USE_TIMESTAMPTff7b72=Tffa657true
Tb4b4b4;Tb4b4b4;
--helpTb4b4b4|-hTff7b72)
Tffa657echo Ta5d6ff"Ta5d6ffUsage: Te6edf3$0Ta5d6ff [--json] [--dry-run] [--allow-existing-branch] [--short-name <name>] [--number N] [--timestamp] <feature_description>Ta5d6ff"
Tffa657echo Ta5d6ff""
Tffa657echo Ta5d6ff"Options:"
Tffa657echo Ta5d6ff" --json Output in JSON format"
Tffa657echo Ta5d6ff" --dry-run Compute branch name without creating the branch"
Tffa657echo Ta5d6ff" --allow-existing-branch Switch to branch if it already exists instead of failing"
Tffa657echo Ta5d6ff" --short-name <name> Provide a custom short name (2-4 words) for the branch"
Tffa657echo Ta5d6ff" --number N Specify branch number manually (overrides auto-detection)"
Tffa657echo Ta5d6ff" --timestamp Use timestamp prefix (YYYYMMDD-HHMMSS) instead of sequential numbering"
Tffa657echo Ta5d6ff" --help, -h Show this help message"
Tffa657echo Ta5d6ff""
Tffa657echo Ta5d6ff"Environment variables:"
Tffa657echo Ta5d6ff" GIT_BRANCH_NAME Use this exact branch name, bypassing all prefix/suffix generation"
Tffa657echo Ta5d6ff""
Tffa657echo Ta5d6ff"Examples:"
Tffa657echo Ta5d6ff"Ta5d6ff Te6edf3$0Ta5d6ff 'Add user authentication system' --short-name 'user-auth'Ta5d6ff"
Tffa657echo Ta5d6ff"Ta5d6ff Te6edf3$0Ta5d6ff 'Implement OAuth2 integration for API' --number 5Ta5d6ff"
Tffa657echo Ta5d6ff"Ta5d6ff Te6edf3$0Ta5d6ff --timestamp --short-name 'user-auth' 'Add user authentication'Ta5d6ff"
Tffa657echo Ta5d6ff"Ta5d6ff GIT_BRANCH_NAME=my-branch Te6edf3$0Ta5d6ff 'feature description'Ta5d6ff"
Tffa657exit T79c0ff0
Tb4b4b4;Tb4b4b4;
*Tff7b72)
Te6edf3ARGSTff7b72+=Tff7b72(Ta5d6ff"Te6edf3$argTa5d6ff"Tff7b72)
Tb4b4b4;Tb4b4b4;
Tff7b72esac
Te6edf3iTff7b72=Tff7b72$((Te6edf3i Tff7b72+ T79c0ff1Tff7b72))
Tff7b72done

Te6edf3FEATURE_DESCRIPTIONTff7b72=Ta5d6ff"Tffd700${Te6edf3ARGSTb4b4b4[*]Tffd700}Ta5d6ff"
Tff7b72if Tff7b72[ -z Ta5d6ff"Te6edf3$FEATURE_DESCRIPTIONTa5d6ff" Tff7b72]Tb4b4b4; Tff7b72then
Tffa657echo Ta5d6ff"Ta5d6ffUsage: Te6edf3$0Ta5d6ff [--json] [--dry-run] [--allow-existing-branch] [--short-name <name>] [--number N] [--timestamp] <feature_description>Ta5d6ff" >Tb4b4b4&T79c0ff2
Tffa657exit T79c0ff1
Tff7b72fi

T8b949e# Trim whitespace and validate description is not empty
Te6edf3FEATURE_DESCRIPTIONTff7b72=Tff7b72$(Tffa657echo Ta5d6ff"Te6edf3$FEATURE_DESCRIPTIONTa5d6ff" Tb4b4b4| sed -E Ta5d6ff's/^[[:space:]]+|[[:space:]]+$//g'Tff7b72)
Tff7b72if Tff7b72[ -z Ta5d6ff"Te6edf3$FEATURE_DESCRIPTIONTa5d6ff" Tff7b72]Tb4b4b4; Tff7b72then
Tffa657echo Ta5d6ff"Error: Feature description cannot be empty or contain only whitespace" >Tb4b4b4&T79c0ff2
Tffa657exit T79c0ff1
Tff7b72fi

T8b949e# Function to get highest number from specs directory
get_highest_from_specsTff7b72(Tff7b72) Tff7b72{
Tffa657local Te6edf3specs_dirTff7b72=Ta5d6ff"Te6edf3$1Ta5d6ff"
Tffa657local Te6edf3highestTff7b72=T79c0ff0

Tff7b72if Tff7b72[ -d Ta5d6ff"Te6edf3$specs_dirTa5d6ff" Tff7b72]Tb4b4b4; Tff7b72then
Tff7b72for dir Tff7b72in Ta5d6ff"Te6edf3$specs_dirTa5d6ff"/*Tb4b4b4; Tff7b72do
Tff7b72[ -d Ta5d6ff"Te6edf3$dirTa5d6ff" Tff7b72] Tff7b72|| Tff7b72continue
Te6edf3dirnameTff7b72=Tff7b72$(basename Ta5d6ff"Te6edf3$dirTa5d6ff"Tff7b72)
T8b949e# Match sequential prefixes (>=3 digits), but skip timestamp dirs.
Tff7b72if Tffa657echo Ta5d6ff"Te6edf3$dirnameTa5d6ff" Tb4b4b4| grep -Eq Ta5d6ff'^[0-9]{3,}-' Tff7b72&& ! Tffa657echo Ta5d6ff"Te6edf3$dirnameTa5d6ff" Tb4b4b4| grep -Eq Ta5d6ff'^[0-9]{8}-[0-9]{6}-'Tb4b4b4; Tff7b72then
Te6edf3numberTff7b72=Tff7b72$(Tffa657echo Ta5d6ff"Te6edf3$dirnameTa5d6ff" Tb4b4b4| grep -Eo Ta5d6ff'^[0-9]+'Tff7b72)
Te6edf3numberTff7b72=Tff7b72$((T79c0ff10#Te6edf3$numberTff7b72))
Tff7b72if Tff7b72[ Ta5d6ff"Te6edf3$numberTa5d6ff" -gt Ta5d6ff"Te6edf3$highestTa5d6ff" Tff7b72]Tb4b4b4; Tff7b72then
Te6edf3highestTff7b72=Te6edf3$number
Tff7b72fi
Tff7b72fi
Tff7b72done
Tff7b72fi

Tffa657echo Ta5d6ff"Te6edf3$highestTa5d6ff"
Tff7b72}

T8b949e# Function to get highest number from git branches
get_highest_from_branchesTff7b72(Tff7b72) Tff7b72{
git branch -a T79c0ff2>/dev/null Tb4b4b4| sed Ta5d6ff's/^[* ]*//; s|^remotes/[^/]*/||' Tb4b4b4| _extract_highest_number
Tff7b72}

T8b949e# Extract the highest sequential feature number from a list of ref names (one per line).
_extract_highest_numberTff7b72(Tff7b72) Tff7b72{
Tffa657local Te6edf3highestTff7b72=T79c0ff0
Tff7b72while Te6edf3IFSTff7b72= Tffa657read -r nameTb4b4b4; Tff7b72do
Tff7b72[ -z Ta5d6ff"Te6edf3$nameTa5d6ff" Tff7b72] Tff7b72&& Tff7b72continue
Tff7b72if Tffa657echo Ta5d6ff"Te6edf3$nameTa5d6ff" Tb4b4b4| grep -Eq Ta5d6ff'^[0-9]{3,}-' Tff7b72&& ! Tffa657echo Ta5d6ff"Te6edf3$nameTa5d6ff" Tb4b4b4| grep -Eq Ta5d6ff'^[0-9]{8}-[0-9]{6}-'Tb4b4b4; Tff7b72then
Te6edf3numberTff7b72=Tff7b72$(Tffa657echo Ta5d6ff"Te6edf3$nameTa5d6ff" Tb4b4b4| grep -Eo Ta5d6ff'^[0-9]+' Tff7b72|| Tffa657echo Ta5d6ff"0"Tff7b72)
Te6edf3numberTff7b72=Tff7b72$((T79c0ff10#Te6edf3$numberTff7b72))
Tff7b72if Tff7b72[ Ta5d6ff"Te6edf3$numberTa5d6ff" -gt Ta5d6ff"Te6edf3$highestTa5d6ff" Tff7b72]Tb4b4b4; Tff7b72then
Te6edf3highestTff7b72=Te6edf3$number
Tff7b72fi
Tff7b72fi
Tff7b72done
Tffa657echo Ta5d6ff"Te6edf3$highestTa5d6ff"
Tff7b72}

T8b949e# Function to get highest number from remote branches without fetching (side-effect-free)
get_highest_from_remote_refsTff7b72(Tff7b72) Tff7b72{
Tffa657local Te6edf3highestTff7b72=T79c0ff0

Tff7b72for remote Tff7b72in Tff7b72$(git remote T79c0ff2>/dev/nullTff7b72)Tb4b4b4; Tff7b72do
Tffa657local remote_highest
Te6edf3remote_highestTff7b72=Tff7b72$(Te6edf3GIT_TERMINAL_PROMPTTff7b72=T79c0ff0 git ls-remote --heads Ta5d6ff"Te6edf3$remoteTa5d6ff" T79c0ff2>/dev/null Tb4b4b4| sed Ta5d6ff's|.*refs/heads/||' Tb4b4b4| _extract_highest_numberTff7b72)
Tff7b72if Tff7b72[ Ta5d6ff"Te6edf3$remote_highestTa5d6ff" -gt Ta5d6ff"Te6edf3$highestTa5d6ff" Tff7b72]Tb4b4b4; Tff7b72then
Te6edf3highestTff7b72=Te6edf3$remote_highest
Tff7b72fi
Tff7b72done

Tffa657echo Ta5d6ff"Te6edf3$highestTa5d6ff"
Tff7b72}

T8b949e# Function to check existing branches and return next available number.
check_existing_branchesTff7b72(Tff7b72) Tff7b72{
Tffa657local Te6edf3specs_dirTff7b72=Ta5d6ff"Te6edf3$1Ta5d6ff"
Tffa657local Te6edf3skip_fetchTff7b72=Ta5d6ff"Tffd700${Te6edf32Tff7b72:-Te6edf3falseTffd700}Ta5d6ff"

Tff7b72if Tff7b72[ Ta5d6ff"Te6edf3$skip_fetchTa5d6ff" Tff7b72= Tffa657true Tff7b72]Tb4b4b4; Tff7b72then
Tffa657local Te6edf3highest_remoteTff7b72=Tff7b72$(get_highest_from_remote_refsTff7b72)
Tffa657local Te6edf3highest_branchTff7b72=Tff7b72$(get_highest_from_branchesTff7b72)
Tff7b72if Tff7b72[ Ta5d6ff"Te6edf3$highest_remoteTa5d6ff" -gt Ta5d6ff"Te6edf3$highest_branchTa5d6ff" Tff7b72]Tb4b4b4; Tff7b72then
Te6edf3highest_branchTff7b72=Te6edf3$highest_remote
Tff7b72fi
Tff7b72else
git fetch --all --prune >/dev/null T79c0ff2>Tb4b4b4&T79c0ff1 Tff7b72|| Tffa657true
Tffa657local Te6edf3highest_branchTff7b72=Tff7b72$(get_highest_from_branchesTff7b72)
Tff7b72fi

Tffa657local Te6edf3highest_specTff7b72=Tff7b72$(get_highest_from_specs Ta5d6ff"Te6edf3$specs_dirTa5d6ff"Tff7b72)

Tffa657local Te6edf3max_numTff7b72=Te6edf3$highest_branch
Tff7b72if Tff7b72[ Ta5d6ff"Te6edf3$highest_specTa5d6ff" -gt Ta5d6ff"Te6edf3$max_numTa5d6ff" Tff7b72]Tb4b4b4; Tff7b72then
Te6edf3max_numTff7b72=Te6edf3$highest_spec
Tff7b72fi

Tffa657echo Tff7b72$((Te6edf3max_num Tff7b72+ T79c0ff1Tff7b72))
Tff7b72}

T8b949e# Function to clean and format a branch name
clean_branch_nameTff7b72(Tff7b72) Tff7b72{
Tffa657local Te6edf3nameTff7b72=Ta5d6ff"Te6edf3$1Ta5d6ff"
Tffa657echo Ta5d6ff"Te6edf3$nameTa5d6ff" Tb4b4b4| tr Ta5d6ff'[:upper:]' Ta5d6ff'[:lower:]' Tb4b4b4| sed Ta5d6ff's/[^a-z0-9]/-/g' Tb4b4b4| sed Ta5d6ff's/-\+/-/g' Tb4b4b4| sed Ta5d6ff's/^-//' Tb4b4b4| sed Ta5d6ff's/-$//'
Tff7b72}

T8b949e# ---------------------------------------------------------------------------
T8b949e# Source common.sh for resolve_template, json_escape, get_repo_root, has_git.
T8b949e#
T8b949e# Search locations in priority order:
T8b949e# 1. .specify/scripts/bash/common.sh under the project root (installed project)
T8b949e# 2. scripts/bash/common.sh under the project root (source checkout fallback)
T8b949e# 3. git-common.sh next to this script (minimal fallback — lacks resolve_template)
T8b949e# ---------------------------------------------------------------------------
Te6edf3SCRIPT_DIRTff7b72=Ta5d6ff"Tff7b72$(Te6edf3CDPATHTff7b72=Ta5d6ff"" Tffa657cd Ta5d6ff"Tff7b72$(dirname Ta5d6ff"Tffd700${Te6edf3BASH_SOURCETb4b4b4[0]Tffd700}Ta5d6ff"Tff7b72)Ta5d6ff" Tff7b72&& Tffa657pwdTff7b72)Ta5d6ff"

T8b949e# Find project root by walking up from the script location
_find_project_rootTff7b72(Tff7b72) Tff7b72{
Tffa657local Te6edf3dirTff7b72=Ta5d6ff"Te6edf3$1Ta5d6ff"
Tff7b72while Tff7b72[ Ta5d6ff"Te6edf3$dirTa5d6ff" !Tff7b72= Ta5d6ff"/" Tff7b72]Tb4b4b4; Tff7b72do
Tff7b72if Tff7b72[ -d Ta5d6ff"Te6edf3$dirTa5d6ff/.specifyTa5d6ff" Tff7b72] Tff7b72|| Tff7b72[ -d Ta5d6ff"Te6edf3$dirTa5d6ff/.gitTa5d6ff" Tff7b72]Tb4b4b4; Tff7b72then
Tffa657echo Ta5d6ff"Te6edf3$dirTa5d6ff"
Tff7b72return T79c0ff0
Tff7b72fi
Te6edf3dirTff7b72=Ta5d6ff"Tff7b72$(dirname Ta5d6ff"Te6edf3$dirTa5d6ff"Tff7b72)Ta5d6ff"
Tff7b72done
Tff7b72return T79c0ff1
Tff7b72}

Te6edf3_common_loadedTff7b72=Tffa657false
Te6edf3_PROJECT_ROOTTff7b72=Tff7b72$(_find_project_root Ta5d6ff"Te6edf3$SCRIPT_DIRTa5d6ff"Tff7b72) Tff7b72|| Tffa657true

Tff7b72if Tff7b72[ -n Ta5d6ff"Te6edf3$_PROJECT_ROOTTa5d6ff" Tff7b72] Tff7b72&& Tff7b72[ -f Ta5d6ff"Te6edf3$_PROJECT_ROOTTa5d6ff/.specify/scripts/bash/common.shTa5d6ff" Tff7b72]Tb4b4b4; Tff7b72then
Tffa657source Ta5d6ff"Te6edf3$_PROJECT_ROOTTa5d6ff/.specify/scripts/bash/common.shTa5d6ff"
Te6edf3_common_loadedTff7b72=Tffa657true
Tff7b72elif Tff7b72[ -n Ta5d6ff"Te6edf3$_PROJECT_ROOTTa5d6ff" Tff7b72] Tff7b72&& Tff7b72[ -f Ta5d6ff"Te6edf3$_PROJECT_ROOTTa5d6ff/scripts/bash/common.shTa5d6ff" Tff7b72]Tb4b4b4; Tff7b72then
Tffa657source Ta5d6ff"Te6edf3$_PROJECT_ROOTTa5d6ff/scripts/bash/common.shTa5d6ff"
Te6edf3_common_loadedTff7b72=Tffa657true
Tff7b72elif Tff7b72[ -f Ta5d6ff"Te6edf3$SCRIPT_DIRTa5d6ff/git-common.shTa5d6ff" Tff7b72]Tb4b4b4; Tff7b72then
Tffa657source Ta5d6ff"Te6edf3$SCRIPT_DIRTa5d6ff/git-common.shTa5d6ff"
Te6edf3_common_loadedTff7b72=Tffa657true
Tff7b72fi

Tff7b72if Tff7b72[ Ta5d6ff"Te6edf3$_common_loadedTa5d6ff" !Tff7b72= Ta5d6ff"true" Tff7b72]Tb4b4b4; Tff7b72then
Tffa657echo Ta5d6ff"Error: Could not locate common.sh or git-common.sh. Please ensure the Specify core scripts are installed." >Tb4b4b4&T79c0ff2
Tffa657exit T79c0ff1
Tff7b72fi

T8b949e# Resolve repository root
Tff7b72if Tffa657type get_repo_root >/dev/null T79c0ff2>Tb4b4b4&T79c0ff1Tb4b4b4; Tff7b72then
Te6edf3REPO_ROOTTff7b72=Tff7b72$(get_repo_rootTff7b72)
Tff7b72elif git rev-parse --show-toplevel >/dev/null T79c0ff2>Tb4b4b4&T79c0ff1Tb4b4b4; Tff7b72then
Te6edf3REPO_ROOTTff7b72=Tff7b72$(git rev-parse --show-toplevelTff7b72)
Tff7b72elif Tff7b72[ -n Ta5d6ff"Te6edf3$_PROJECT_ROOTTa5d6ff" Tff7b72]Tb4b4b4; Tff7b72then
Te6edf3REPO_ROOTTff7b72=Ta5d6ff"Te6edf3$_PROJECT_ROOTTa5d6ff"
Tff7b72else
Tffa657echo Ta5d6ff"Error: Could not determine repository root." >Tb4b4b4&T79c0ff2
Tffa657exit T79c0ff1
Tff7b72fi

T8b949e# Check if git is available at this repo root
Tff7b72if Tffa657type has_git >/dev/null T79c0ff2>Tb4b4b4&T79c0ff1Tb4b4b4; Tff7b72then
Tff7b72if has_git Ta5d6ff"Te6edf3$REPO_ROOTTa5d6ff"Tb4b4b4; Tff7b72then
Te6edf3HAS_GITTff7b72=Tffa657true
Tff7b72else
Te6edf3HAS_GITTff7b72=Tffa657false
Tff7b72fi
Tff7b72elif git -C Ta5d6ff"Te6edf3$REPO_ROOTTa5d6ff" rev-parse --is-inside-work-tree >/dev/null T79c0ff2>Tb4b4b4&T79c0ff1Tb4b4b4; Tff7b72then
Te6edf3HAS_GITTff7b72=Tffa657true
Tff7b72else
Te6edf3HAS_GITTff7b72=Tffa657false
Tff7b72fi

Tffa657cd Ta5d6ff"Te6edf3$REPO_ROOTTa5d6ff"

Te6edf3SPECS_DIRTff7b72=Ta5d6ff"Te6edf3$REPO_ROOTTa5d6ff/specsTa5d6ff"

T8b949e# Function to generate branch name with stop word filtering
generate_branch_nameTff7b72(Tff7b72) Tff7b72{
Tffa657local Te6edf3descriptionTff7b72=Ta5d6ff"Te6edf3$1Ta5d6ff"

Tffa657local Te6edf3stop_wordsTff7b72=Ta5d6ff"Ta5d6ff^(i|a|an|the|to|for|of|in|on|at|by|with|from|is|are|was|were|be|been|being|have|has|had|do|does|did|will|would|should|could|can|may|might|must|shall|this|that|these|those|my|your|our|their|want|need|add|get|set)$Ta5d6ff"

Tffa657local Te6edf3clean_nameTff7b72=Tff7b72$(Tffa657echo Ta5d6ff"Te6edf3$descriptionTa5d6ff" Tb4b4b4| tr Ta5d6ff'[:upper:]' Ta5d6ff'[:lower:]' Tb4b4b4| sed Ta5d6ff's/[^a-z0-9]/ /g'Tff7b72)

Tffa657local Te6edf3meaningful_wordsTff7b72=Tff7b72(Tff7b72)
Tff7b72for word Tff7b72in Te6edf3$clean_nameTb4b4b4; Tff7b72do
Tff7b72[ -z Ta5d6ff"Te6edf3$wordTa5d6ff" Tff7b72] Tff7b72&& Tff7b72continue
Tff7b72if ! Tffa657echo Ta5d6ff"Te6edf3$wordTa5d6ff" Tb4b4b4| grep -qiE Ta5d6ff"Te6edf3$stop_wordsTa5d6ff"Tb4b4b4; Tff7b72then
Tff7b72if Tff7b72[ Tffd700${#Te6edf3wordTffd700} -ge T79c0ff3 Tff7b72]Tb4b4b4; Tff7b72then
Te6edf3meaningful_wordsTff7b72+=Tff7b72(Ta5d6ff"Te6edf3$wordTa5d6ff"Tff7b72)
Tff7b72elif Tffa657echo Ta5d6ff"Te6edf3$descriptionTa5d6ff" Tb4b4b4| grep -qw -- Ta5d6ff"Tffd700${Te6edf3wordTb4b4b4^^Tffd700}Ta5d6ff"Tb4b4b4; Tff7b72then
Te6edf3meaningful_wordsTff7b72+=Tff7b72(Ta5d6ff"Te6edf3$wordTa5d6ff"Tff7b72)
Tff7b72fi
Tff7b72fi
Tff7b72done

Tff7b72if Tff7b72[ Tffd700${#Te6edf3meaningful_wordsTb4b4b4[@]Tffd700} -gt T79c0ff0 Tff7b72]Tb4b4b4; Tff7b72then
Tffa657local Te6edf3max_wordsTff7b72=T79c0ff3
Tff7b72if Tff7b72[ Tffd700${#Te6edf3meaningful_wordsTb4b4b4[@]Tffd700} -eq T79c0ff4 Tff7b72]Tb4b4b4; Tff7b72then Te6edf3max_wordsTff7b72=T79c0ff4Tb4b4b4; Tff7b72fi

Tffa657local Te6edf3resultTff7b72=Ta5d6ff""
Tffa657local Te6edf3countTff7b72=T79c0ff0
Tff7b72for word Tff7b72in Ta5d6ff"Tffd700${Te6edf3meaningful_wordsTb4b4b4[@]Tffd700}Ta5d6ff"Tb4b4b4; Tff7b72do
Tff7b72if Tff7b72[ Te6edf3$count -ge Te6edf3$max_words Tff7b72]Tb4b4b4; Tff7b72then Tff7b72breakTb4b4b4; Tff7b72fi
Tff7b72if Tff7b72[ -n Ta5d6ff"Te6edf3$resultTa5d6ff" Tff7b72]Tb4b4b4; Tff7b72then Te6edf3resultTff7b72=Ta5d6ff"Te6edf3$resultTa5d6ff-Ta5d6ff"Tb4b4b4; Tff7b72fi
Te6edf3resultTff7b72=Ta5d6ff"Te6edf3$resultTe6edf3$wordTa5d6ff"
Te6edf3countTff7b72=Tff7b72$((Te6edf3count Tff7b72+ T79c0ff1Tff7b72))
Tff7b72done
Tffa657echo Ta5d6ff"Te6edf3$resultTa5d6ff"
Tff7b72else
Tffa657local Te6edf3cleanedTff7b72=Tff7b72$(clean_branch_name Ta5d6ff"Te6edf3$descriptionTa5d6ff"Tff7b72)
Tffa657echo Ta5d6ff"Te6edf3$cleanedTa5d6ff" Tb4b4b4| tr Ta5d6ff'-' Ta5d6ff'\n' Tb4b4b4| grep -v Ta5d6ff'^$' Tb4b4b4| head -3 Tb4b4b4| tr Ta5d6ff'\n' Ta5d6ff'-' Tb4b4b4| sed Ta5d6ff's/-$//'
Tff7b72fi
Tff7b72}

T8b949e# Check for GIT_BRANCH_NAME env var override (exact branch name, no prefix/suffix)
Tff7b72if Tff7b72[ -n Ta5d6ff"Tffd700${Te6edf3GIT_BRANCH_NAMETff7b72:-Tffd700}Ta5d6ff" Tff7b72]Tb4b4b4; Tff7b72then
Te6edf3BRANCH_NAMETff7b72=Ta5d6ff"Te6edf3$GIT_BRANCH_NAMETa5d6ff"
T8b949e# Extract FEATURE_NUM from the branch name if it starts with a numeric prefix
T8b949e# Check timestamp pattern first (YYYYMMDD-HHMMSS-) since it also matches the simpler ^[0-9]+ pattern
Tff7b72if Tffa657echo Ta5d6ff"Te6edf3$BRANCH_NAMETa5d6ff" Tb4b4b4| grep -Eq Ta5d6ff'^[0-9]{8}-[0-9]{6}-'Tb4b4b4; Tff7b72then
Te6edf3FEATURE_NUMTff7b72=Tff7b72$(Tffa657echo Ta5d6ff"Te6edf3$BRANCH_NAMETa5d6ff" Tb4b4b4| grep -Eo Ta5d6ff'^[0-9]{8}-[0-9]{6}'Tff7b72)
Te6edf3BRANCH_SUFFIXTff7b72=Ta5d6ff"Tffd700${Te6edf3BRANCH_NAMETb4b4b4#Tffd700${Te6edf3FEATURE_NUMTffd700}Tb4b4b4-Tffd700}Ta5d6ff"
Tff7b72elif Tffa657echo Ta5d6ff"Te6edf3$BRANCH_NAMETa5d6ff" Tb4b4b4| grep -Eq Ta5d6ff'^[0-9]+-'Tb4b4b4; Tff7b72then
Te6edf3FEATURE_NUMTff7b72=Tff7b72$(Tffa657echo Ta5d6ff"Te6edf3$BRANCH_NAMETa5d6ff" Tb4b4b4| grep -Eo Ta5d6ff'^[0-9]+'Tff7b72)
Te6edf3BRANCH_SUFFIXTff7b72=Ta5d6ff"Tffd700${Te6edf3BRANCH_NAMETb4b4b4#Tffd700${Te6edf3FEATURE_NUMTffd700}Tb4b4b4-Tffd700}Ta5d6ff"
Tff7b72else
Te6edf3FEATURE_NUMTff7b72=Ta5d6ff"Te6edf3$BRANCH_NAMETa5d6ff"
Te6edf3BRANCH_SUFFIXTff7b72=Ta5d6ff"Te6edf3$BRANCH_NAMETa5d6ff"
Tff7b72fi
Tff7b72else
T8b949e# Generate branch name
Tff7b72if Tff7b72[ -n Ta5d6ff"Te6edf3$SHORT_NAMETa5d6ff" Tff7b72]Tb4b4b4; Tff7b72then
Te6edf3BRANCH_SUFFIXTff7b72=Tff7b72$(clean_branch_name Ta5d6ff"Te6edf3$SHORT_NAMETa5d6ff"Tff7b72)
Tff7b72else
Te6edf3BRANCH_SUFFIXTff7b72=Tff7b72$(generate_branch_name Ta5d6ff"Te6edf3$FEATURE_DESCRIPTIONTa5d6ff"Tff7b72)
Tff7b72fi

T8b949e# Warn if --number and --timestamp are both specified
Tff7b72if Tff7b72[ Ta5d6ff"Te6edf3$USE_TIMESTAMPTa5d6ff" Tff7b72= Tffa657true Tff7b72] Tff7b72&& Tff7b72[ -n Ta5d6ff"Te6edf3$BRANCH_NUMBERTa5d6ff" Tff7b72]Tb4b4b4; Tff7b72then
>Tb4b4b4&T79c0ff2 Tffa657echo Ta5d6ff"[specify] Warning: --number is ignored when --timestamp is used"
Te6edf3BRANCH_NUMBERTff7b72=Ta5d6ff""
Tff7b72fi

T8b949e# Determine branch prefix
Tff7b72if Tff7b72[ Ta5d6ff"Te6edf3$USE_TIMESTAMPTa5d6ff" Tff7b72= Tffa657true Tff7b72]Tb4b4b4; Tff7b72then
Te6edf3FEATURE_NUMTff7b72=Tff7b72$(date +%Y%m%d-%H%M%STff7b72)
Te6edf3BRANCH_NAMETff7b72=Ta5d6ff"Tffd700${Te6edf3FEATURE_NUMTffd700}Ta5d6ff-Tffd700${Te6edf3BRANCH_SUFFIXTffd700}Ta5d6ff"
Tff7b72else
Tff7b72if Tff7b72[ -z Ta5d6ff"Te6edf3$BRANCH_NUMBERTa5d6ff" Tff7b72]Tb4b4b4; Tff7b72then
Tff7b72if Tff7b72[ Ta5d6ff"Te6edf3$DRY_RUNTa5d6ff" Tff7b72= Tffa657true Tff7b72] Tff7b72&& Tff7b72[ Ta5d6ff"Te6edf3$HAS_GITTa5d6ff" Tff7b72= Tffa657true Tff7b72]Tb4b4b4; Tff7b72then
Te6edf3BRANCH_NUMBERTff7b72=Tff7b72$(check_existing_branches Ta5d6ff"Te6edf3$SPECS_DIRTa5d6ff" Tffa657trueTff7b72)
Tff7b72elif Tff7b72[ Ta5d6ff"Te6edf3$DRY_RUNTa5d6ff" Tff7b72= Tffa657true Tff7b72]Tb4b4b4; Tff7b72then
Te6edf3HIGHESTTff7b72=Tff7b72$(get_highest_from_specs Ta5d6ff"Te6edf3$SPECS_DIRTa5d6ff"Tff7b72)
Te6edf3BRANCH_NUMBERTff7b72=Tff7b72$((Te6edf3HIGHEST Tff7b72+ T79c0ff1Tff7b72))
Tff7b72elif Tff7b72[ Ta5d6ff"Te6edf3$HAS_GITTa5d6ff" Tff7b72= Tffa657true Tff7b72]Tb4b4b4; Tff7b72then
Te6edf3BRANCH_NUMBERTff7b72=Tff7b72$(check_existing_branches Ta5d6ff"Te6edf3$SPECS_DIRTa5d6ff"Tff7b72)
Tff7b72else
Te6edf3HIGHESTTff7b72=Tff7b72$(get_highest_from_specs Ta5d6ff"Te6edf3$SPECS_DIRTa5d6ff"Tff7b72)
Te6edf3BRANCH_NUMBERTff7b72=Tff7b72$((Te6edf3HIGHEST Tff7b72+ T79c0ff1Tff7b72))
Tff7b72fi
Tff7b72fi

Te6edf3FEATURE_NUMTff7b72=Tff7b72$(Tffa657printf Ta5d6ff"%03d" Ta5d6ff"Tff7b72$((T79c0ff10#Te6edf3$BRANCH_NUMBERTff7b72))Ta5d6ff"Tff7b72)
Te6edf3BRANCH_NAMETff7b72=Ta5d6ff"Tffd700${Te6edf3FEATURE_NUMTffd700}Ta5d6ff-Tffd700${Te6edf3BRANCH_SUFFIXTffd700}Ta5d6ff"
Tff7b72fi
Tff7b72fi

T8b949e# GitHub enforces a 244-byte limit on branch names
Te6edf3MAX_BRANCH_LENGTHTff7b72=T79c0ff244
_byte_lengthTff7b72(Tff7b72) Tff7b72{ Tffa657printf Ta5d6ff'%s' Ta5d6ff"Te6edf3$1Ta5d6ff" Tb4b4b4| Te6edf3LC_ALLTff7b72=C wc -c Tb4b4b4| tr -d Ta5d6ff' 'Tb4b4b4; Tff7b72}
Te6edf3BRANCH_BYTE_LENTff7b72=Tff7b72$(_byte_length Ta5d6ff"Te6edf3$BRANCH_NAMETa5d6ff"Tff7b72)
Tff7b72if Tff7b72[ -n Ta5d6ff"Tffd700${Te6edf3GIT_BRANCH_NAMETff7b72:-Tffd700}Ta5d6ff" Tff7b72] Tff7b72&& Tff7b72[ Ta5d6ff"Te6edf3$BRANCH_BYTE_LENTa5d6ff" -gt Te6edf3$MAX_BRANCH_LENGTH Tff7b72]Tb4b4b4; Tff7b72then
>Tb4b4b4&T79c0ff2 Tffa657echo Ta5d6ff"Ta5d6ffError: GIT_BRANCH_NAME must be 244 bytes or fewer in UTF-8. Provided value is Tffd700${Te6edf3BRANCH_BYTE_LENTffd700}Ta5d6ff bytes.Ta5d6ff"
Tffa657exit T79c0ff1
Tff7b72elif Tff7b72[ Ta5d6ff"Te6edf3$BRANCH_BYTE_LENTa5d6ff" -gt Te6edf3$MAX_BRANCH_LENGTH Tff7b72]Tb4b4b4; Tff7b72then
Te6edf3PREFIX_LENGTHTff7b72=Tff7b72$(( Tffd700${#Te6edf3FEATURE_NUMTffd700} Tff7b72+ T79c0ff1 Tff7b72))
Te6edf3MAX_SUFFIX_LENGTHTff7b72=Tff7b72$((Te6edf3MAX_BRANCH_LENGTH Tff7b72- Te6edf3PREFIX_LENGTHTff7b72))

Te6edf3TRUNCATED_SUFFIXTff7b72=Tff7b72$(Tffa657echo Ta5d6ff"Te6edf3$BRANCH_SUFFIXTa5d6ff" Tb4b4b4| cut -c1-Te6edf3$MAX_SUFFIX_LENGTHTff7b72)
Te6edf3TRUNCATED_SUFFIXTff7b72=Tff7b72$(Tffa657echo Ta5d6ff"Te6edf3$TRUNCATED_SUFFIXTa5d6ff" Tb4b4b4| sed Ta5d6ff's/-$//'Tff7b72)

Te6edf3ORIGINAL_BRANCH_NAMETff7b72=Ta5d6ff"Te6edf3$BRANCH_NAMETa5d6ff"
Te6edf3BRANCH_NAMETff7b72=Ta5d6ff"Tffd700${Te6edf3FEATURE_NUMTffd700}Ta5d6ff-Tffd700${Te6edf3TRUNCATED_SUFFIXTffd700}Ta5d6ff"

>Tb4b4b4&T79c0ff2 Tffa657echo Ta5d6ff"[specify] Warning: Branch name exceeded GitHub's 244-byte limit"
>Tb4b4b4&T79c0ff2 Tffa657echo Ta5d6ff"Ta5d6ff[specify] Original: Te6edf3$ORIGINAL_BRANCH_NAMETa5d6ff (Tffd700${#Te6edf3ORIGINAL_BRANCH_NAMETffd700}Ta5d6ff bytes)Ta5d6ff"
>Tb4b4b4&T79c0ff2 Tffa657echo Ta5d6ff"Ta5d6ff[specify] Truncated to: Te6edf3$BRANCH_NAMETa5d6ff (Tffd700${#Te6edf3BRANCH_NAMETffd700}Ta5d6ff bytes)Ta5d6ff"
Tff7b72fi

Tff7b72if Tff7b72[ Ta5d6ff"Te6edf3$DRY_RUNTa5d6ff" !Tff7b72= Tffa657true Tff7b72]Tb4b4b4; Tff7b72then
Tff7b72if Tff7b72[ Ta5d6ff"Te6edf3$HAS_GITTa5d6ff" Tff7b72= Tffa657true Tff7b72]Tb4b4b4; Tff7b72then
Te6edf3branch_create_errorTff7b72=Ta5d6ff""
Tff7b72if ! Te6edf3branch_create_errorTff7b72=Tff7b72$(git checkout -q -b Ta5d6ff"Te6edf3$BRANCH_NAMETa5d6ff" T79c0ff2>Tb4b4b4&T79c0ff1Tff7b72)Tb4b4b4; Tff7b72then
Te6edf3current_branchTff7b72=Ta5d6ff"Tff7b72$(git rev-parse --abbrev-ref HEAD T79c0ff2>/dev/null Tff7b72|| Tffa657trueTff7b72)Ta5d6ff"
Tff7b72if git branch --list Ta5d6ff"Te6edf3$BRANCH_NAMETa5d6ff" Tb4b4b4| grep -q .Tb4b4b4; Tff7b72then
Tff7b72if Tff7b72[ Ta5d6ff"Te6edf3$ALLOW_EXISTINGTa5d6ff" Tff7b72= Tffa657true Tff7b72]Tb4b4b4; Tff7b72then
Tff7b72if Tff7b72[ Ta5d6ff"Te6edf3$current_branchTa5d6ff" Tff7b72= Ta5d6ff"Te6edf3$BRANCH_NAMETa5d6ff" Tff7b72]Tb4b4b4; Tff7b72then
:
Tff7b72elif ! Te6edf3switch_branch_errorTff7b72=Tff7b72$(git checkout -q Ta5d6ff"Te6edf3$BRANCH_NAMETa5d6ff" T79c0ff2>Tb4b4b4&T79c0ff1Tff7b72)Tb4b4b4; Tff7b72then
>Tb4b4b4&T79c0ff2 Tffa657echo Ta5d6ff"Ta5d6ffError: Failed to switch to existing branch 'Te6edf3$BRANCH_NAMETa5d6ff'. Please resolve any local changes or conflicts and try again.Ta5d6ff"
Tff7b72if Tff7b72[ -n Ta5d6ff"Te6edf3$switch_branch_errorTa5d6ff" Tff7b72]Tb4b4b4; Tff7b72then
>Tb4b4b4&T79c0ff2 Tffa657printf Ta5d6ff'%s\n' Ta5d6ff"Te6edf3$switch_branch_errorTa5d6ff"
Tff7b72fi
Tffa657exit T79c0ff1
Tff7b72fi
Tff7b72elif Tff7b72[ Ta5d6ff"Te6edf3$USE_TIMESTAMPTa5d6ff" Tff7b72= Tffa657true Tff7b72]Tb4b4b4; Tff7b72then
>Tb4b4b4&T79c0ff2 Tffa657echo Ta5d6ff"Ta5d6ffError: Branch 'Te6edf3$BRANCH_NAMETa5d6ff' already exists. Rerun to get a new timestamp or use a different --short-name.Ta5d6ff"
Tffa657exit T79c0ff1
Tff7b72else
>Tb4b4b4&T79c0ff2 Tffa657echo Ta5d6ff"Ta5d6ffError: Branch 'Te6edf3$BRANCH_NAMETa5d6ff' already exists. Please use a different feature name or specify a different number with --number.Ta5d6ff"
Tffa657exit T79c0ff1
Tff7b72fi
Tff7b72else
>Tb4b4b4&T79c0ff2 Tffa657echo Ta5d6ff"Ta5d6ffError: Failed to create git branch 'Te6edf3$BRANCH_NAMETa5d6ff'.Ta5d6ff"
Tff7b72if Tff7b72[ -n Ta5d6ff"Te6edf3$branch_create_errorTa5d6ff" Tff7b72]Tb4b4b4; Tff7b72then
>Tb4b4b4&T79c0ff2 Tffa657printf Ta5d6ff'%s\n' Ta5d6ff"Te6edf3$branch_create_errorTa5d6ff"
Tff7b72else
>Tb4b4b4&T79c0ff2 Tffa657echo Ta5d6ff"Please check your git configuration and try again."
Tff7b72fi
Tffa657exit T79c0ff1
Tff7b72fi
Tff7b72fi
Tff7b72else
>Tb4b4b4&T79c0ff2 Tffa657echo Ta5d6ff"Ta5d6ff[specify] Warning: Git repository not detected; skipped branch creation for Te6edf3$BRANCH_NAMETa5d6ff"
Tff7b72fi

Tffa657printf Ta5d6ff'# To persist: export SPECIFY_FEATURE=%q\n' Ta5d6ff"Te6edf3$BRANCH_NAMETa5d6ff" >Tb4b4b4&T79c0ff2
Tff7b72fi

Tff7b72if Te6edf3$JSON_MODETb4b4b4; Tff7b72then
Tff7b72if Tffa657command -v jq >/dev/null T79c0ff2>Tb4b4b4&T79c0ff1Tb4b4b4; Tff7b72then
Tff7b72if Tff7b72[ Ta5d6ff"Te6edf3$DRY_RUNTa5d6ff" Tff7b72= Tffa657true Tff7b72]Tb4b4b4; Tff7b72then
jq -cn Tffea00\
--arg branch_name Ta5d6ff"Te6edf3$BRANCH_NAMETa5d6ff" Tffea00\
--arg feature_num Ta5d6ff"Te6edf3$FEATURE_NUMTa5d6ff" Tffea00\
Ta5d6ff'{BRANCH_NAME:$branch_name,FEATURE_NUM:$feature_num,DRY_RUN:true}'
Tff7b72else
jq -cn Tffea00\
--arg branch_name Ta5d6ff"Te6edf3$BRANCH_NAMETa5d6ff" Tffea00\
--arg feature_num Ta5d6ff"Te6edf3$FEATURE_NUMTa5d6ff" Tffea00\
Ta5d6ff'{BRANCH_NAME:$branch_name,FEATURE_NUM:$feature_num}'
Tff7b72fi
Tff7b72else
Tff7b72if Tffa657type json_escape >/dev/null T79c0ff2>Tb4b4b4&T79c0ff1Tb4b4b4; Tff7b72then
Te6edf3_je_branchTff7b72=Tff7b72$(json_escape Ta5d6ff"Te6edf3$BRANCH_NAMETa5d6ff"Tff7b72)
Te6edf3_je_numTff7b72=Tff7b72$(json_escape Ta5d6ff"Te6edf3$FEATURE_NUMTa5d6ff"Tff7b72)
Tff7b72else
Te6edf3_je_branchTff7b72=Ta5d6ff"Te6edf3$BRANCH_NAMETa5d6ff"
Te6edf3_je_numTff7b72=Ta5d6ff"Te6edf3$FEATURE_NUMTa5d6ff"
Tff7b72fi
Tff7b72if Tff7b72[ Ta5d6ff"Te6edf3$DRY_RUNTa5d6ff" Tff7b72= Tffa657true Tff7b72]Tb4b4b4; Tff7b72then
Tffa657printf Ta5d6ff'{"BRANCH_NAME":"%s","FEATURE_NUM":"%s","DRY_RUN":true}\n' Ta5d6ff"Te6edf3$_je_branchTa5d6ff" Ta5d6ff"Te6edf3$_je_numTa5d6ff"
Tff7b72else
Tffa657printf Ta5d6ff'{"BRANCH_NAME":"%s","FEATURE_NUM":"%s"}\n' Ta5d6ff"Te6edf3$_je_branchTa5d6ff" Ta5d6ff"Te6edf3$_je_numTa5d6ff"
Tff7b72fi
Tff7b72fi
Tff7b72else
Tffa657echo Ta5d6ff"Ta5d6ffBRANCH_NAME: Te6edf3$BRANCH_NAMETa5d6ff"
Tffa657echo Ta5d6ff"Ta5d6ffFEATURE_NUM: Te6edf3$FEATURE_NUMTa5d6ff"
Tff7b72if Tff7b72[ Ta5d6ff"Te6edf3$DRY_RUNTa5d6ff" !Tff7b72= Tffa657true Tff7b72]Tb4b4b4; Tff7b72then
Tffa657printf Ta5d6ff'# To persist in your shell: export SPECIFY_FEATURE=%q\n' Ta5d6ff"Te6edf3$BRANCH_NAMETa5d6ff"
Tff7b72fi
Tff7b72fi

Served by rngit 1.5.2 - Generated in 0.09s